package com.zlzlib.libscan;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.text.Layout;
import android.text.StaticLayout;
import android.text.TextPaint;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.View;




/**
 * Created by zlz on 2018/9/14.
 * 扫描框
 */
public class MyScanBoxView extends View {

    private Context context;
    //遮罩层的颜色  , 扫描框的颜色  , 扫描角的颜色 , 提示文字的颜色
    private int maskColor, boxColor, conColor, tipTextColor, tipTextBg;
    //提示文字
    private String tipText = "";
    //框的宽度，框的高度 ，框的定位
    private int boxW, boxH, boxTopOffset;
    //框与整个控件的比例
    private float box_w_dio = 0, box_h_dio = 0;
    //框的线宽  四个角的线宽 四个角的长度  文字大小  文字和框的间距
    private float boxStroke, conStroke, conLength, tipTextSize, tipTextMargin;
    //是否只识别框内的部分
    private boolean isOnlyScanArea = true;
    //提示文字在上面还是下面
    private boolean isTipTop = false;
    //是否固定提示文字背景的大小
    private boolean isTipBgFixedW = true;
    //扫描框是否居中显示
    private boolean isBoxCenter = true;
    //识别的框
    private Rect mFramingRect;
    //画笔
    private Paint mPaint;
    private TextPaint mTipPaint;
    //提示文字框
    private StaticLayout tipTextSl;
    //提示文字框圆角
    private int tipBackgroundRadius = 10;
    //扫描线
    private Bitmap scanLineBitmap = null;
    //扫描线上下间距  扫描线移动的距离
    private float mScanLineMargin = 10, mScanLineLeft = 0;
    //扫描线移动的距离  动画延迟时间  动画总时间
    private int mMoveStepDistance = 10, mAnimDelayTime, mAnimTime;
    //扫描线移动方式 true==来回移动  false  == 直接跳转回来
    private boolean isScanMoveBack = true;

    public MyScanBoxView(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.context = context;
        init(attrs);
    }

    private void init(AttributeSet attrs) {
        TypedArray array = getContext().obtainStyledAttributes(attrs, R.styleable.ScanView);
        maskColor = array.getColor(R.styleable.ScanView_mask_color, Color.parseColor("#33FFFFFF"));
        boxColor = array.getColor(R.styleable.ScanView_box_color, Color.WHITE);
        conColor = array.getColor(R.styleable.ScanView_con_color, Color.GREEN);
        tipTextColor = array.getColor(R.styleable.ScanView_tip_text_color, Color.WHITE);
        tipTextBg = array.getColor(R.styleable.ScanView_tip_text_bg, Color.parseColor("#22000000"));
        tipText = array.getString(R.styleable.ScanView_tip_text);
        boxW = array.getDimensionPixelSize(R.styleable.ScanView_box_w, Utils.dip2px(context, 200));
        box_w_dio = array.getFloat(R.styleable.ScanView_box_w_dio, box_w_dio);
        boxH = array.getDimensionPixelSize(R.styleable.ScanView_box_h, Utils.dip2px(context, 200));
        box_h_dio = array.getFloat(R.styleable.ScanView_box_h_dio, box_h_dio);
        boxTopOffset = array.getDimensionPixelSize(R.styleable.ScanView_box_top_offset, Utils.dip2px(context, 0));
        boxStroke = array.getDimension(R.styleable.ScanView_box_stroke, Utils.dip2px(context, 1f));
        conStroke = array.getDimension(R.styleable.ScanView_con_stroke, Utils.dip2px(context, 3f));
        conLength = array.getDimension(R.styleable.ScanView_con_length, Utils.dip2px(context, 10f));
        tipTextSize = array.getDimension(R.styleable.ScanView_tip_text_size, Utils.dip2px(context, 16f));
        tipTextMargin = array.getDimension(R.styleable.ScanView_tip_text_margin, Utils.dip2px(context, 10f));
        isOnlyScanArea = array.getBoolean(R.styleable.ScanView_is_only_scan_area, isOnlyScanArea);
        isTipTop = array.getBoolean(R.styleable.ScanView_is_tip_top, isTipTop);
        isTipBgFixedW = array.getBoolean(R.styleable.ScanView_is_tip_bg_fixed_w, isTipBgFixedW);
        isBoxCenter = array.getBoolean(R.styleable.ScanView_is_box_center, isBoxCenter);
        isScanMoveBack = array.getBoolean(R.styleable.ScanView_is_box_center, isScanMoveBack);
        mAnimTime = array.getInt(R.styleable.ScanView_anim_time, 1200);
        Drawable scanLine = array.getDrawable(R.styleable.ScanView_scan_line);
        if (null != scanLine) {
            scanLineBitmap = ((BitmapDrawable) scanLine).getBitmap();
        }
        array.recycle();
        mMoveStepDistance = Utils.dip2px(context, 2);
        mPaint = new Paint();
        mTipPaint = new TextPaint();
        mTipPaint.setTextSize(tipTextSize);
        mTipPaint.setColor(tipTextColor);
        mAnimDelayTime = (int) ((1.0f * mAnimTime * mMoveStepDistance) / boxW);
        initText();
    }

    private void initText() {
        //初始化提示的文字
        if (!TextUtils.isEmpty(tipText)) {
            if (isTipBgFixedW) {
                tipTextSl = new StaticLayout(tipText, mTipPaint, boxW - 2 * tipBackgroundRadius,
                        Layout.Alignment.ALIGN_CENTER, 1.0f, 0, true);
            } else {
                tipTextSl = new StaticLayout(tipText, mTipPaint, Utils.getScreenResolution(getContext()).x,
                        Layout.Alignment.ALIGN_CENTER, 1.0f, 0, true);
            }
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        if (box_w_dio > 0 && box_w_dio <= 1) {
            boxW = (int) (MeasureSpec.getSize(widthMeasureSpec) * box_w_dio);
        }
        if (box_h_dio > 0 && box_h_dio <= 1) {
            boxH = (int) (MeasureSpec.getSize(heightMeasureSpec) * box_h_dio);
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {
        if (mFramingRect == null) {
            return;
        }
        drawMask(canvas);
        drawBorderLine(canvas);
        drawCornerLine(canvas);
        drawTipText(canvas);
        drawScanLine(canvas);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        calFramingRect();
    }

    //扫描框区域
    private void calFramingRect() {
        int leftOffset = (getWidth() - boxW) / 2;
        int top;
        if (isBoxCenter) {
            top = (getHeight() - boxH) / 2 + boxTopOffset;
        } else {
            top = boxTopOffset;
        }
        mFramingRect = new Rect(leftOffset, top, leftOffset + boxW, top + boxH);
        mScanLineLeft = mFramingRect.left + conStroke / 2;
    }

    //得到扫描的区域  传入相机数据的高度
    public Rect getScanBoxAreaRect(int previewHeight, int previewWidth) {
        if (isOnlyScanArea && getVisibility() == View.VISIBLE) {
            //将扫描框的大小区域映射到摄像区
            Rect rect = new Rect(mFramingRect);
            float ratioH = 1.0f * previewHeight / getMeasuredHeight();
            float ratioW = 1.0f * previewWidth / getMeasuredWidth();
            float centerX = rect.exactCenterX();
            float centerY = rect.exactCenterY();
            float offsetH = (previewHeight - getMeasuredHeight()) * 0.5f;
            float offsetW = (previewWidth - getMeasuredWidth()) * 0.5f;
            float newHalfWidth = rect.width() / 2f * ratioW;
            float newHalfHeight = rect.height() / 2f * ratioH;
            int pad = 20;
            rect.left = (int) (centerX - newHalfWidth + offsetW - pad);
            rect.right = (int) (centerX + newHalfWidth + offsetW + pad);
            rect.top = (int) (centerY - newHalfHeight + offsetH - pad);
            rect.bottom = (int) (centerY + newHalfHeight + offsetH + pad);
            return rect;
        } else {
            return null;
        }
    }

    /**
     * 画遮罩层
     */
    private void drawMask(Canvas canvas) {
        int width = canvas.getWidth();
        int height = canvas.getHeight();
        if (maskColor != Color.TRANSPARENT) {
            mPaint.setStyle(Paint.Style.FILL);
            mPaint.setColor(maskColor);
            //通过扫描的区域确定遮罩的区域
            //上边区域
            canvas.drawRect(0, 0, width, mFramingRect.top, mPaint);
            //左边区域
            canvas.drawRect(0, mFramingRect.top, mFramingRect.left, mFramingRect.bottom + 1, mPaint);
            //右边区域
            canvas.drawRect(mFramingRect.right + 1, mFramingRect.top, width, mFramingRect.bottom + 1, mPaint);
            //底部区域
            canvas.drawRect(0, mFramingRect.bottom + 1, width, height, mPaint);
        }
    }

    /**
     * 画边框线
     */
    private void drawBorderLine(Canvas canvas) {
        if (boxStroke > 0) {
            mPaint.setStyle(Paint.Style.STROKE);
            mPaint.setColor(boxColor);
            mPaint.setStrokeWidth(boxStroke);
            canvas.drawRect(mFramingRect, mPaint);
        }
    }

    /**
     * 画四个直角的线
     */
    private void drawCornerLine(Canvas canvas) {
        if (conStroke > 0 && conLength > 0) {
            mPaint.setStyle(Paint.Style.STROKE);
            mPaint.setColor(conColor);
            mPaint.setStrokeWidth(conStroke);
            //分别化8根线
            float ff = conStroke / 2;
            canvas.drawLine(mFramingRect.left - ff, mFramingRect.top,
                    mFramingRect.left - ff + conLength, mFramingRect.top, mPaint);
            canvas.drawLine(mFramingRect.left, mFramingRect.top - ff,
                    mFramingRect.left, mFramingRect.top - ff + conLength, mPaint);
            canvas.drawLine(mFramingRect.right + ff, mFramingRect.top,
                    mFramingRect.right + ff - conLength, mFramingRect.top, mPaint);
            canvas.drawLine(mFramingRect.right, mFramingRect.top - ff, mFramingRect.right,
                    mFramingRect.top - ff + conLength, mPaint);
            canvas.drawLine(mFramingRect.left - ff, mFramingRect.bottom,
                    mFramingRect.left - ff + conLength, mFramingRect.bottom, mPaint);
            canvas.drawLine(mFramingRect.left, mFramingRect.bottom + ff, mFramingRect.left,
                    mFramingRect.bottom + ff - conLength, mPaint);
            canvas.drawLine(mFramingRect.right + ff, mFramingRect.bottom,
                    mFramingRect.right + ff - conLength, mFramingRect.bottom, mPaint);
            canvas.drawLine(mFramingRect.right, mFramingRect.bottom + ff, mFramingRect.right,
                    mFramingRect.bottom + ff - conLength, mPaint);
        }
    }

    /**
     * 画提示文本
     */
    private void drawTipText(Canvas canvas) {
        if (TextUtils.isEmpty(tipText) || tipTextSl == null) {
            return;
        }
        mPaint.setColor(tipTextBg);
        mPaint.setStyle(Paint.Style.FILL);
        //绘制背景的位置  判断位置是在框上面还是下面
        RectF rectF;
        float left, right, top, bottom;
        if (isTipBgFixedW) {
            left = mFramingRect.left;
            right = mFramingRect.right;
        } else {
            //跟随文字变化 获得文字的长度
            Rect tipRect = new Rect();
            mTipPaint.getTextBounds(tipText, 0, tipText.length(), tipRect);
            //通过文字的长度计算位置
            left = (canvas.getWidth() - tipRect.width()) / 2 - tipBackgroundRadius;
            right = left + tipRect.width() + 2 * tipBackgroundRadius;
        }
        if (isTipTop) {
            top = mFramingRect.top - tipTextMargin - tipTextSl.getHeight() - tipBackgroundRadius;
            bottom = mFramingRect.top - tipTextMargin + tipBackgroundRadius;
        } else {
            top = mFramingRect.bottom + tipTextMargin - tipBackgroundRadius;
            bottom = mFramingRect.bottom + tipTextMargin + tipTextSl.getHeight() + tipBackgroundRadius;
        }
        rectF = new RectF(left, top, right, bottom);
        canvas.drawRoundRect(rectF, tipBackgroundRadius, tipBackgroundRadius, mPaint);
        canvas.save();
        //移动提示文字的位置
        float dx, dy;
        if (isTipBgFixedW) {
            //左移
            dx = mFramingRect.left;
        } else {
            dx = 0;
        }
        if (isTipTop) {
            dy = mFramingRect.top - tipTextMargin - tipTextSl.getHeight();
        } else {
            dy = mFramingRect.bottom + tipTextMargin;
        }
        canvas.translate(dx, dy);
        tipTextSl.draw(canvas);
        canvas.restore();
    }

    private void drawScanLine(Canvas canvas) {
        if (null != scanLineBitmap) {
            float ff = conStroke / 2;
            RectF lineRect = new RectF(mScanLineLeft, mFramingRect.top + ff + mScanLineMargin,
                    mScanLineLeft + scanLineBitmap.getWidth(), mFramingRect.bottom - ff - mScanLineMargin);
            canvas.drawBitmap(scanLineBitmap, null, lineRect, mPaint);
            // 处理非网格扫描图片的情况
            mScanLineLeft += mMoveStepDistance;
            float scanLineSize = scanLineBitmap.getWidth();
            if (isScanMoveBack) {
                if (mScanLineLeft + scanLineSize > mFramingRect.right - ff || mScanLineLeft < mFramingRect.left + ff) {
                    mMoveStepDistance = -mMoveStepDistance;
                }
            } else {
                if (mScanLineLeft + scanLineSize > mFramingRect.right - ff) {
                    mScanLineLeft = mFramingRect.left + ff + 0.5f;
                }
            }
            postInvalidateDelayed(mAnimDelayTime, mFramingRect.left, mFramingRect.top, mFramingRect.right, mFramingRect.bottom);
        }
    }

    public void setBoxWH(int boxW, int boxH) {
        this.boxW = boxW;
        this.boxH = boxH;
        calFramingRect();
        postInvalidate();
    }

    public void setConColor(int conColor) {
        this.conColor = conColor;
    }

    public void setMaskColor(int maskColor) {
        this.maskColor = maskColor;
    }

    public void setBoxColor(int boxColor) {
        this.boxColor = boxColor;
    }

    public void setTipTextColor(int tipTextColor) {
        this.tipTextColor = tipTextColor;
    }

    public void setTipTextBg(int tipTextBg) {
        this.tipTextBg = tipTextBg;
    }

    public void setTipText(String tipText) {
        this.tipText = tipText;
        initText();
    }

    public void setScanLineBitmap(Bitmap scanLineBitmap) {
        this.scanLineBitmap = scanLineBitmap;
    }

    public void setScanLineBitmap(Drawable drawable, int degree) {
        if (drawable == null) {
            return;
        }
        scanLineBitmap = ((BitmapDrawable) drawable).getBitmap();
        //旋转角度
        scanLineBitmap = Utils.adjustPhotoRotation(scanLineBitmap, degree);
    }
}
